package com.code.wordhelper.utils;

import com.code.wordhelper.model.ImageByteData;
import com.code.wordhelper.model.ImageData;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.util.Units;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Decoder;

import java.awt.*;
import java.io.*;
import java.util.List;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 根据模板生成对应内容
 */
public class WordTemplateUtils {
    private final static Pattern PLACE_HOLDER = Pattern.compile("\\$\\{([\\w\\.]+)\\}");
    private final static Pattern FIELD_PLACE_HOLDER = Pattern.compile("\\[([\\w]+)\\]");
    private final static Pattern MULTI_FIELD_PLACE_HOLDER = Pattern.compile("\\[([\\w\\.]+)\\]");

    private final static String PLACE_HOLDER_PREFIX = "$";
    private final static String PLACE_HOLDER_SUFFIX = "}";
    private final static String FIELD_PLACE_HOLDER_PREFIX = "[";
    private final static String FIELD_PLACE_HOLDER_SUFFIX = "]";
    private final static String MULTI_FIELD_SEPERATOR = ".";
    private final static String MULTI_FIELD_SEPERATOR_SPLIT = "\\.";
    private final static String FIELD_INDEX = "index";
    private final static String GAP_PIC = "    ";
    private final static String GAP_TEXT = "                    ";
    private final static List<String> complexTables = Arrays.asList("detectionResult", "diseaseResults");

    private static Logger logger = LoggerFactory.getLogger(WordTemplateUtils.class);

    public static void replaceParagraphs(XWPFDocument document, Map<String, Object> dataMap) throws Exception {
        List<XWPFParagraph> paragraphList = document.getParagraphs();

        for (int i = 0; i < paragraphList.size(); i++) {
            XWPFParagraph paragraph = paragraphList.get(i);
            if (!PatternUtils.match(paragraph.getText(), PLACE_HOLDER)) {
                continue;
            }
            replaceParagraph(paragraph, dataMap);
        }
    }

    public static void replaceTables(XWPFDocument document, Map<String, Object> dataMap) throws Exception {
        List<XWPFTable> tableList = document.getTables();

        for (XWPFTable table : tableList) {
            XWPFTableCell firstTableCell = table.getRow(0).getCell(0);

            String tableHeaderInfo = firstTableCell.getText();
            //检查是否存在表格标志
            if (PatternUtils.match(tableHeaderInfo, PLACE_HOLDER)) {
                String placeholder = PatternUtils.regex(tableHeaderInfo, PLACE_HOLDER, 1);
                if (!dataMap.containsKey(placeholder) || complexTables.contains(placeholder)) {
                    continue;
                }

                List<Object> objs = (List<Object>) dataMap.get(placeholder);

                tableHeaderInfo = tableHeaderInfo.replace("${" + placeholder + "}", "");
                setCellValue(firstTableCell, tableHeaderInfo);
                replaceTable(table, dataMap, objs);
            }
        }
    }

    private static void replaceTable(XWPFTable table, Map<String, Object> dataMap, List<Object> objs) throws Exception {
        //查询需要需要循环的行
        XmlCursor xmlCursor = table.getCTTbl().newCursor();
        XWPFParagraph imgParagraph = null;
        XWPFParagraph textParagraph = null;

        List<XWPFTableRow> tableRows = table.getRows();
        int n = 0;
        int m = 0;
        for (int i = 1; i < tableRows.size(); i++) {
            //需要循环的标记
            int needRoundRow = -1;
            List<XWPFTableCell> tableCells = tableRows.get(i).getTableCells();
            for (XWPFTableCell tableCell : tableCells) {
                if (PatternUtils.match(tableCell.getText(), FIELD_PLACE_HOLDER) && !tableCell.getText().contains("detectionResults")) {
                    needRoundRow = i;
                    break;
                }
            }

            // 找到匹配项，需要复制该行
            if (needRoundRow != -1) {
                for (int k = 0; k < objs.size(); k++) {
                    XWPFTableRow newRow = table.insertNewTableRow(needRoundRow + k + 1);
                    newRow.getCtRow().setTrPr(table.getRow(needRoundRow).getCtRow().getTrPr());

                    //复制行并解析属性
                    for (int j = 0; j < tableCells.size(); j++) {
                        XWPFTableCell tableCell = tableCells.get(j);
                        XWPFTableCell newCell = newRow.addNewTableCell();

                        // 如果存在循环属性
                        if (PatternUtils.match(tableCell.getText(), MULTI_FIELD_PLACE_HOLDER) && tableCell.getText().contains(MULTI_FIELD_SEPERATOR)) {
                        } else if (PatternUtils.match(tableCell.getText(), FIELD_PLACE_HOLDER)) {
                            String field = PatternUtils.regex(tableCell.getText(), FIELD_PLACE_HOLDER, 1);
                            Object cellValue = null;
                            if (FIELD_INDEX.equalsIgnoreCase(field)) {
                                cellValue = String.valueOf(k + 1);
                            } else {
                                cellValue = ClassUtils.getFieldValue(objs.get(k), field);
                                if (cellValue == null) {
                                    continue;
                                }
                                if (cellValue instanceof ImageData) {
                                    if (m % 2 == 0) {
                                        xmlCursor.toEndToken();
                                        xmlCursor.toNextToken();
                                        imgParagraph = table.getBody().insertNewParagraph(xmlCursor);
                                        imgParagraph.setAlignment(ParagraphAlignment.CENTER);

                                        xmlCursor.toEndToken();
                                        xmlCursor.toNextToken();
                                        textParagraph = table.getBody().insertNewParagraph(xmlCursor);
                                        textParagraph.setAlignment(ParagraphAlignment.CENTER);
                                        //设置左右边距
//                                        textParagraph.setIndentationLeft(100);
//                                        textParagraph.setIndentationRight(100);
                                    }
                                    if (m % 2 != 0) {
                                        //每行只存放两张图片
                                        imgParagraph.createRun().setText(GAP_PIC, 0);
                                        textParagraph.createRun().setText(GAP_TEXT, 0);
                                    }

                                    ImageData imageData = (ImageData) cellValue;
                                    XWPFRun run = imgParagraph.createRun();
                                    run.addPicture(new FileInputStream(imageData.getUrl()), format(imageData.getExt()).nativeId, imageData.getFilename(), Units.toEMU(imageData.getHeight()), Units.toEMU(imageData.getWidth()));

                                    cellValue = "图片" + (n + 1) + "-" + (++m);
                                    textParagraph.createRun().setText(cellValue.toString(), 0);
                                }
                            }

                            copyCellAndSetValue(tableCell, newCell, cellValue.toString(), false);
                        } else if (PatternUtils.match(tableCell.getText(), PLACE_HOLDER)) {
                            // 如果是普通属性
                            String prop = PatternUtils.regex(tableCell.getText(), PLACE_HOLDER, 1);
                            copyCellAndSetValue(tableCell, newCell, dataMap.get(prop).toString(), false);
                        } else {
                            copyCellAndSetValue(tableCell, newCell, "", false);
                        }
                    }
                    i++;
                }

                // 删除模板行
                table.removeRow(needRoundRow);
                i--;
            } else {
                //如果没有需要循环的属性则查看是否有文本替换的标记
                for (XWPFTableCell tableCell : tableCells) {
                    if (PatternUtils.match(tableCell.getText(), PLACE_HOLDER)) {
                        // 如果是普通属性
                        replaceCellTemplate(tableCell, dataMap);
                    }
                }
            }
        }
    }

    // 递归拆分单元格
    private static int replaceComplexTable2(XWPFTableCell tableCell, XWPFTableCell newCell, XWPFTable table, Object obj, int row, int col, int sum) throws Exception {
        //如果是多层属性，就拆分单元格
        String multiField = PatternUtils.regex(tableCell.getText(), MULTI_FIELD_PLACE_HOLDER, 1);
        String[] multiFields = multiField.split(MULTI_FIELD_SEPERATOR_SPLIT);
        Object templateObj = obj;

        //暂时不处理两层以上的替换
        if (multiFields.length > 2) {
            return 0;
        }
        if (multiFields.length < 0) {
            return 0;
        }

        Object fieldValue = ClassUtils.getFieldValue(templateObj, multiFields[0]);
        if (fieldValue instanceof Collection) {
            // 如果是集合对象
            List<Object> fieldValueList = (List<Object>) fieldValue;
            TableTools.splitCellsVertically(table, row, col, fieldValueList.size());

            for (int i = 0; i < fieldValueList.size(); i++) {
                Object temObj = fieldValueList.get(i);
                XWPFTableCell cell = table.getRow(row + i).getCell(col);
                cell.setText(ClassUtils.getFieldValue(temObj, multiFields[1]).toString());
            }
        } else {
            //如果是普通对象

        }
        return 1;
    }

    public static void replaceTableBridges(XWPFDocument document, Map<String, Object> dataMap) throws Exception {
        //查询需要需要循环的行
        XWPFTable table = null;
        List results = null;
        for (XWPFTable tab : document.getTables()) {
            XWPFTableCell firstTableCell = tab.getRow(0).getCell(0);

            String tableHeaderInfo = firstTableCell.getText();
            //检查是否存在表格标志
            if (PatternUtils.match(tableHeaderInfo, PLACE_HOLDER)) {
                String placeholder = PatternUtils.regex(tableHeaderInfo, PLACE_HOLDER, 1);
                if (!dataMap.containsKey(placeholder) || !complexTables.contains(placeholder)) {
                    continue;
                }

                tableHeaderInfo = tableHeaderInfo.replace("${" + placeholder + "}", "");
                setCellValue(firstTableCell, tableHeaderInfo);
                table = tab;
                results = (List) dataMap.get(placeholder);
                replaceTableBridge(table, results, dataMap);
            }
        }
    }

    public static void replaceTableBridge(XWPFTable table, List results, Map<String, Object> dataMap) throws Exception {
        //查询需要需要循环的行
        List<XWPFTableRow> tableRows = table.getRows();

        List<XWPFTableCell> tableCells = table.getRow(1).getTableCells();
        int[] ones = new int[tableCells.size()];
        int n = table.getNumberOfRows();

        int oldRowLen = tableRows.size();
        List<Integer> deleteRow = new ArrayList<>();
        for (int i = 1; i < oldRowLen; i++) {
            int needRoundRow = -1;
            tableCells = table.getRow(i).getTableCells();
            for (XWPFTableCell tableCell : tableCells) {
                if (PatternUtils.match(tableCell.getText(), FIELD_PLACE_HOLDER)) {
                    needRoundRow = i;
                    break;
                }
            }

            // 找到匹配项，需要复制该行
            if (needRoundRow != -1) {
                deleteRow.add(needRoundRow);
                for (Object result : results) {
                    setNull(ones, tableCells.size());

                    List fieldValueList = ClassUtils.getCollectionFieldName(result);
                    if (fieldValueList == null) {
                        continue;
                    }
                    for (int k = 0; k < fieldValueList.size(); k++) {
                        boolean strike = false;
                        if (ClassUtils.checkFields(fieldValueList.get(k), "strike")) {
                            strike = (boolean) ClassUtils.getFieldValue(fieldValueList.get(k), "strike");
                        }

                        //复制行并解析属性
                        XWPFTableRow newRow = table.insertNewTableRow(n + k);
                        newRow.getCtRow().setTrPr(table.getRow(1).getCtRow().getTrPr());

                        for (int j = 0; j < tableCells.size(); j++) {
                            XWPFTableCell tableCell = tableCells.get(j);
                            XWPFTableCell newCell = newRow.addNewTableCell();

                            //如果是一层
                            if (PatternUtils.match(tableCell.getText(), FIELD_PLACE_HOLDER)) {
                                ones[j] = 1;
                            } else if (PatternUtils.match(tableCell.getText(), MULTI_FIELD_PLACE_HOLDER)) {
                                String multiField = PatternUtils.regex(tableCell.getText(), MULTI_FIELD_PLACE_HOLDER, 1);
                                String[] multiFields = multiField.split(MULTI_FIELD_SEPERATOR_SPLIT);
                                Object fieldValue = ClassUtils.getFieldValue(fieldValueList.get(k), multiFields[1]);
                                if (fieldValue == null) {
                                    fieldValue = "";
                                }
                                copyCellAndSetValue(tableCell, newCell, fieldValue.toString(), strike);
                            } else {
                                copyCellAndSetValue(tableCell, newCell, "", strike);
                            }
                        }
                    }
                    // 解析一层属性
                    for (int s = 0; s < tableCells.size(); s++) {
                        if (1 == ones[s]) {
                            TableTools.mergeCellsVertically(table, s, n, n + fieldValueList.size());
                            String fieldName = PatternUtils.regex(tableCells.get(s).getText(), FIELD_PLACE_HOLDER, 1);
                            table.getRow(n).getCell(s).setText(ClassUtils.getFieldValue(result, fieldName).toString());
                        }
                    }
                    n = n + fieldValueList.size();
                }
            } else {
                //复制行数据
                copyRow(table, i, n);
                for (int j = 0; j < tableCells.size(); j++) {
                    XWPFTableCell tableCell = table.getRow(n).getCell(j);

                    if (PatternUtils.match(tableCell.getText(), PLACE_HOLDER)) {
                        replaceCellTemplate(tableCell, dataMap);
                    }
                }
                n++;
            }
        }
        // 删除模板行
        for (int i = oldRowLen - 1; i > 0; i--) {
            table.removeRow(i);
        }
    }

    public static void replaceHeaders(XWPFDocument document, Map<String, Object> dataMap) throws Exception {
        List<XWPFHeader> headerList = document.getHeaderList();
        for (int i = 0; i < headerList.size(); i++) {
            XWPFHeader header = headerList.get(i);

            for (XWPFParagraph paragraph : header.getParagraphs()) {
                replaceParagraph(paragraph, dataMap);
            }
        }
    }

    //生成目录
    public static void generateTOC(Document doc) throws FileNotFoundException, IOException {
//        Paragraph parainserted = new Paragraph(doc);
//        TextRange tr = parainserted.appendText("目 录");
//        tr.getCharacterFormat().setBold(true);
//        tr.getCharacterFormat().setTextColor(Color.gray);
//        doc.getSections().get(1).getParagraphs().insert(0, parainserted);
//        parainserted.getFormat().setHorizontalAlignment(HorizontalAlignment.Center);
//
//        //通过域代码添加目录表
//        TableOfContent toc = new TableOfContent(doc, "{\\o \"1-3\" \\h \\z \\u}");
//        doc.getSections().get(1).getParagraphs().get(0).appendTOC(1, 3);
//        doc.updateTableOfContents();
    }

    private static void setNull(int[] ones, int len) {
        for (int s = 0; s < len; s++) {
            ones[s] = -1;
        }
    }

    public static void copyRow(XWPFTable table, int source, int insertRowIndex) {
        XWPFTableRow sourceRow = table.getRow(source);
        XWPFTableRow targetRow = table.insertNewTableRow(insertRowIndex);
        targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
        List<XWPFTableCell> sourceCells = sourceRow.getTableCells();
        for (XWPFTableCell sourceCell : sourceCells) {
            XWPFTableCell newCell = targetRow.addNewTableCell();
            newCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
            newCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);//垂直居中
            CTPPr pPr = sourceCell.getCTTc().getPList().get(0).getPPr();
            if (pPr != null && pPr.getJc() != null && pPr.getJc().getVal() != null) {
                CTTc cttc = newCell.getCTTc();
                CTP ctp = cttc.getPList().get(0);
                CTPPr ctppr = ctp.getPPr();
                if (ctppr == null) {
                    ctppr = ctp.addNewPPr();
                }
                CTJc ctjc = ctppr.getJc();
                if (ctjc == null) {
                    ctjc = ctppr.addNewJc();
                }
                ctjc.setVal(pPr.getJc().getVal()); //水平居中
            }

            //得到复制单元格的段落
            List<XWPFParagraph> sourceParagraphs = sourceCell.getParagraphs();
            if (StringUtils.isEmpty(sourceCell.getText())) {
                continue;
            }
            XWPFParagraph sourceParagraph = sourceParagraphs.get(0);
            List<XWPFParagraph> targetParagraphs = newCell.getParagraphs();
            if (CollectionUtils.isEmpty(targetParagraphs)) {
                XWPFParagraph ph = newCell.addParagraph();
                ph.setAlignment(ParagraphAlignment.CENTER);
                ph.getCTP().setPPr(sourceParagraph.getCTP().getPPr());
                XWPFRun run = ph.getRuns().isEmpty() ? ph.createRun() : ph.getRuns().get(0);
                run.setFontFamily(sourceParagraph.getRuns().get(0).getFontFamily());
                run.setText(sourceCell.getText(), 0);
            } else {
                XWPFParagraph ph = targetParagraphs.get(0);
                ph.setAlignment(ParagraphAlignment.CENTER);
                ph.getCTP().setPPr(sourceParagraph.getCTP().getPPr());
                XWPFRun run = ph.getRuns().isEmpty() ? ph.createRun() : ph.getRuns().get(0);
                run.setFontFamily(sourceParagraph.getRuns().get(0).getFontFamily());
                run.setText(sourceCell.getText(), 0);
            }
        }
    }


    private static void replaceParagraph(XWPFParagraph paragraph, Map<String, Object> dataMap) throws Exception {
        List<XWPFRun> runList = paragraph.getRuns();

        if (CollectionUtils.isEmpty(runList)) {
            return;
        }
        int prev = -1;
        int prevIdx = 0;
        int last = -1;
        int lastIdx = 0;
        for (int i = 0; i < runList.size(); i++) {
            if (!CollectionUtils.isEmpty(runList.get(i).getEmbeddedPictures())) {
                continue;
            }
            if (StringUtils.isEmpty(runList.get(i).text())) {
                continue;
            }
            String runText = runList.get(i).text();
            if (runText.contains(PLACE_HOLDER_PREFIX)) {
                if (prev == i) {
                    prevIdx = runText.indexOf(PLACE_HOLDER_PREFIX, prevIdx + 1);
                } else {
                    prevIdx = runText.indexOf(PLACE_HOLDER_PREFIX);
                }
                prev = i;
            }
            if (runText.contains(PLACE_HOLDER_SUFFIX)) {
                if (last == i) {
                    lastIdx = runText.indexOf(PLACE_HOLDER_SUFFIX, prevIdx + 1);
                } else {
                    lastIdx = runText.indexOf(PLACE_HOLDER_SUFFIX);
                }
                last = i;
                if (prev == -1 || last == -1) {
                    continue;
                }
                if (prevIdx == -1 || lastIdx == -1) {
                    continue;
                }

                String placeholderKey = concatRun(runList, prev, last, prevIdx, lastIdx);
                if (StringUtils.isEmpty(placeholderKey) || !PatternUtils.match(placeholderKey, PLACE_HOLDER)) {
                    continue;
                }
                logger.info("placeholderKey:{}", placeholderKey);
                replaceTemplate(runList, placeholderKey, prev, last, prevIdx, lastIdx, dataMap);
            }
            //判断当前run是否存在多个替换
            if (runText.indexOf(PLACE_HOLDER_PREFIX, prevIdx + 1) != -1) {
                i--;
            }
        }
    }

    private static void replaceCellParagraph(XWPFParagraph paragraph, Map<String, Object> dataMap) throws Exception {
        List<XWPFRun> runList = paragraph.getRuns();

        if (CollectionUtils.isEmpty(runList)) {
            return;
        }
        int prev = -1;
        int prevIdx = 0;
        int last = -1;
        int lastIdx = 0;
        for (int i = 0; i < runList.size(); i++) {
            if (StringUtils.isEmpty(runList.get(i).text())) {
                continue;
            }
            String runText = runList.get(i).text();
            if (runText.contains(FIELD_PLACE_HOLDER_PREFIX)) {
                if (prev == i) {
                    prevIdx = runText.indexOf(FIELD_PLACE_HOLDER_PREFIX, prevIdx + 1);
                } else {
                    prevIdx = runText.indexOf(FIELD_PLACE_HOLDER_PREFIX);
                }
                prev = i;
            }
            if (runText.contains(FIELD_PLACE_HOLDER_SUFFIX)) {
                if (last == i) {
                    lastIdx = runText.indexOf(FIELD_PLACE_HOLDER_SUFFIX, prevIdx + 1);
                } else {
                    lastIdx = runText.indexOf(FIELD_PLACE_HOLDER_SUFFIX);
                }
                last = i;
                if (prev == -1 || last == -1) {
                    continue;
                }
                if (prevIdx == -1 || lastIdx == -1) {
                    continue;
                }

                String placeholderKey = concatRun(runList, prev, last, prevIdx, lastIdx);
                if (StringUtils.isEmpty(placeholderKey) || !PatternUtils.match(placeholderKey, PLACE_HOLDER)) {
                    continue;
                }
                logger.info("cellPlaceholderKey:{}", placeholderKey);
                replaceTemplate(runList, placeholderKey, prev, last, prevIdx, lastIdx, dataMap);
            }
            //判断当前run是否存在多个替换
            if (runText.indexOf(FIELD_PLACE_HOLDER_PREFIX, prevIdx + 1) != -1) {
                i--;
            }
        }
    }

    private static void replaceTemplate(List<XWPFRun> runList, String placeholderKey, int prev, int last, int prevIdx, int lastIdx, Map<String, Object> dataMap) throws Exception {
        String mapKey = PatternUtils.regex(placeholderKey, PLACE_HOLDER, 1);
        logger.info("mapKey:{}", mapKey);
        //检查占位符是几层
        String[] mapKeys = mapKey.split(MULTI_FIELD_SEPERATOR_SPLIT);
        Object value = null;
        if (mapKeys.length == 2) {
            Object tempObj = dataMap.get(mapKeys[0]);
            value = ClassUtils.getFieldValue(tempObj, mapKeys[1]);
        } else if (mapKeys.length == 1) {
            value = dataMap.get(mapKeys[0]);
        }

        XWPFParagraph paragraph = runList.get(0).getParagraph();
        XmlCursor cursor = paragraph.getCTP().newCursor();

        logger.info("value:---{}", value);
        if (value == null) {
            value = "";
        }
        replaceRunTemplate(runList, prev, last, prevIdx, lastIdx);
        if (value instanceof String) {
            runList.get(prev).setText(value.toString());
        }
        if (value instanceof ImageData) {
            ImageData imageData = (ImageData) value;
            CTSectPr sectPr = runList.get(0).getDocument().getDocument().getBody().getSectPr();
            double width = sectPr.getPgSz().getW().doubleValue();
            double height = sectPr.getPgSz().getH().doubleValue();

            runList.get(prev).addPicture(new FileInputStream(imageData.getUrl()), format(imageData.getExt()).nativeId, imageData.getFilename(), Units.toEMU(imageData.getWidth()), Units.toEMU(imageData.getHeight()));
//                runList.get(prev).addPicture(new FileInputStream(imageData.getUrl()), format(imageData.getExt()).nativeId, imageData.getFilename(),  Units.toEMU(width), Units.toEMU(height));
        }
        if (value instanceof ImageByteData) {
            ImageByteData imageByteData = (ImageByteData) value;
            String imgBase64 = imageByteData.getBase64().replaceAll("data:image/png;base64,", "");
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] bus = decoder.decodeBuffer(imgBase64);

            runList.get(prev).addPicture(new ByteArrayInputStream(bus), format(imageByteData.getExt()).nativeId, imageByteData.getFilename(), Units.toEMU(imageByteData.getWidth()), Units.toEMU(imageByteData.getHeight()));
        }
        if (value instanceof List) {
            List<Object> objs = (List<Object>) value;

            //如果是多张图片就两张一行
            for (int i = 0; i < objs.size(); i++) {
                Object obj = objs.get(i);
                if (obj instanceof ImageData) {
                    ImageData imageData = (ImageData) obj;
                    if (i % 2 == 0) {
//                            paragraph.insertNewRun(prev + i / 2 + 1).addCarriageReturn();
//                            paragraph.createRun().setText("");
                        if (i != 0) {
                            paragraph.createRun().addCarriageReturn();
                        }
                    } else {
//                            paragraph.createRun().setText(GAP_PIC, 0);
//                            paragraph.insertNewRun(prev + i / 2 + 1).setText(GAP_PIC, 0);
                    }
                    paragraph.createRun().addPicture(new FileInputStream(imageData.getUrl()), format(imageData.getExt()).nativeId, imageData.getFilename(), Units.toEMU(imageData.getWidth()), Units.toEMU(imageData.getHeight()));
//                        runList.get(i).addPicture(new FileInputStream(imageData.getUrl()), format(imageData.getExt()).nativeId, imageData.getFilename(), Units.toEMU(imageData.getWidth()), Units.toEMU(imageData.getHeight()));
                } else if (obj instanceof String) {
                    if (i != 0) {
                        cursor.toEndToken();
                        cursor.toNextToken();
                        XWPFParagraph newParagraph = paragraph.getDocument().insertNewParagraph(cursor);
                        newParagraph.getCTP().setPPr(paragraph.getCTP().getPPr());
                        paragraph = newParagraph;
                    }
                    paragraph.setAlignment(ParagraphAlignment.LEFT);
                    //循环多个段落
                    String text = "(" + (i + 1) + ")" + obj.toString();
                    XWPFRun run = paragraph.createRun();
                    run.getCTR().setRPr(runList.get(prev).getCTR().getRPr());
                    run.setText(text, 0);
                }
            }
        }

    }

    private static void replaceRunTemplate(List<XWPFRun> runList, int prev, int last, int prevIdx, int lastIdx) {
        String prevRunText = runList.get(prev).text();
        String lastRunText = runList.get(last).text();

        logger.info("prev:{}-prevIdx:{}, last:{}-lastIdx:{}", prev, prevIdx, last, lastIdx);
        if (prev == last) {
            if (lastIdx == prevRunText.length() - 1) {
                runList.get(prev).setText(prevRunText.substring(0, prevIdx), 0);
            } else {
                prevRunText = prevRunText.substring(0, prevIdx) + prevRunText.substring(lastIdx + 1);
                runList.get(prev).setText(prevRunText, 0);
            }
        } else {
            runList.get(prev).setText(prevRunText.substring(0, prevIdx), 0);

            if (lastIdx == lastRunText.length() - 1) {
                runList.get(last).setText("", 0);
            } else {
                lastRunText = lastRunText.substring(lastIdx + 1);
                runList.get(last).setText(lastRunText, 0);
            }

            for (int i = prev + 1; i < last; i++) {
                runList.get(i).getCTR().newCursor().removeXml();
            }
        }
    }

    private static void replaceCellTemplate(XWPFTableCell tableCell, Map<String, Object> dataMap) throws Exception {
        for (XWPFParagraph paragraph : tableCell.getParagraphs()) {
            replaceParagraph(paragraph, dataMap);
        }
    }

    /**
     * 复制字体样式
     */
    private static void setTypeface(XWPFParagraph sourcePar, XWPFParagraph targetPar) {
        XWPFRun sourceRun = sourcePar.getRuns().get(0);
        XWPFRun targetRun = targetPar.getRuns().get(0);

        targetRun.setFontFamily(sourceRun.getFontFamily());
        targetRun.setFontSize(sourceRun.getFontSize() != -1 ? sourceRun.getFontSize() : 10);
        targetRun.setBold(sourceRun.isBold());
        targetRun.setColor(sourceRun.getColor());
        targetRun.setItalic(sourceRun.isItalic());
        targetRun.setKerning(sourceRun.getKerning());
        targetRun.setUnderline(sourceRun.getUnderline());
    }

    public static void copyCellAndSetValue(XWPFTableCell sourceCell, XWPFTableCell targetCell, String text, boolean strike) {
        //段落属性
        List<XWPFParagraph> sourceCellParagraphs = sourceCell.getParagraphs();
        if (sourceCellParagraphs == null || sourceCellParagraphs.size() <= 0) {
            return;
        }
        XWPFParagraph sourcePar = sourceCellParagraphs.get(0);
        XWPFParagraph targetPar = targetCell.getParagraphs().get(0);

        // 设置段落的样式
        targetPar.getCTP().setPPr(sourcePar.getCTP().getPPr());

        List<XWPFRun> sourceParRuns = sourcePar.getRuns();
        if (sourceParRuns != null && sourceParRuns.size() > 0) {
            // 如果当前cell中有run
            List<XWPFRun> runs = targetPar.getRuns();
            Optional.ofNullable(runs).ifPresent(rs -> rs.stream().forEach(r -> r.setText("", 0)));
            if (runs != null && runs.size() > 0) {
                runs.get(0).setText(text, 0);
                runs.get(0).setStrikeThrough(strike);
            } else {
                XWPFRun cellR = targetPar.createRun();
                cellR.setText(text, 0);
                cellR.setStrikeThrough(strike);
                // 设置列的样式位模板的样式
                targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
            }
            setTypeface(sourcePar, targetPar);
        } else {
            targetCell.setText(text);
            List<XWPFRun> runs = targetPar.getRuns();
            if (runs != null && runs.size() > 0) {
                runs.get(0).setText(text, 0);
                runs.get(0).setStrikeThrough(strike);
            } else {
                XWPFRun newRun = targetPar.createRun();
                newRun.setText(text, 0);
                newRun.setStrikeThrough(strike);
            }
        }
    }

    public static void setCellValue(XWPFTableCell tableCell, String text) {
        List<XWPFParagraph> paragraphs = tableCell.getParagraphs();
        if (paragraphs == null || paragraphs.size() <= 0) {
            tableCell.setText(text);
        }
        XWPFParagraph paragraph = paragraphs.get(0);
        XWPFParagraph newParagraph = tableCell.addParagraph();
        newParagraph.getCTP().setPPr(paragraph.getCTP().getPPr());

        XWPFRun run = newParagraph.createRun();
        run.getCTR().setRPr(paragraph.getRuns().get(0).getCTR().getRPr());
        run.setText(text, 0);

        for (int i = 0; i < paragraphs.size() - 1; i++) {
            tableCell.removeParagraph(i);
        }

    }

    private static String concatRun(List<XWPFRun> runList) {
        StringBuffer stringBuffer = new StringBuffer();
        for (XWPFRun run : runList) {
            stringBuffer.append(run.text());
        }
        return stringBuffer.toString();
    }

    private static String concatRun(List<XWPFRun> runList, int start, int end, int prevIdx, int lastIdx) {
        if (start == end) {
            return runList.get(start).text().substring(prevIdx, lastIdx + 1);
        }
        StringBuffer stringBuffer = new StringBuffer();

        for (int i = start; i <= end; i++) {
            if (i == start) {
                stringBuffer.append(runList.get(i).text().substring(prevIdx));
            } else if (i == end) {
                stringBuffer.append(runList.get(i).text().substring(0, lastIdx + 1));
            } else {
                stringBuffer.append(runList.get(i).text());
            }
        }
        return stringBuffer.toString();
    }

    private static PictureData.PictureType format(String ext) {
        if ("JPEG".equalsIgnoreCase(ext)) {
            return PictureData.PictureType.JPEG;
        } else if ("PNG".equalsIgnoreCase(ext)) {
            return PictureData.PictureType.PNG;
        } else if ("SVG".equalsIgnoreCase(ext)) {
            return PictureData.PictureType.SVG;
        } else if ("GIF".equalsIgnoreCase(ext)) {
            return PictureData.PictureType.GIF;
        }
        return PictureData.PictureType.JPEG;
    }


    public static void main(String[] args) throws Exception {
        OPCPackage pack = POIXMLDocument.openPackage("C:\\Users\\10419\\Desktop\\检测模板.docx");
        XWPFDocument document = new XWPFDocument(pack);//创建word对象

//        XmlCursor xmlCursor = document.getTableArray(0).getCTTbl().newCursor();
//        xmlCursor.toEndToken();
//        System.out.println(xmlCursor.toNextToken());
//        System.out.println(xmlCursor.getTextValue());

//        Map<String, Object> dataMap = buildData();
//        replaceTables(document, dataMap);
//        replaceParagraphs(document, dataMap);
//        System.out.println("ss".substring(0, 0));
//        System.out.println("ss".substring(0, 1));
//        System.out.println("ss".substring(1, 1));
        replaceHeaders(document, buildData());

//        XWPFParagraph paragraph = document.createParagraph();
//        paragraph.setAlignment(ParagraphAlignment.CENTER);
//        paragraph.createRun().addPicture(new FileInputStream("C:\\Users\\10419\\Desktop\\pic\\cc.jpeg"), format("jpeg").nativeId, "cc", Units.toEMU(100), Units.toEMU(50));
//        paragraph.createRun().setText("             ", 0);
//        paragraph.createRun().addPicture(new FileInputStream("C:\\Users\\10419\\Desktop\\pic\\cc.jpeg"), format("jpeg").nativeId, "cc", Units.toEMU(100), Units.toEMU(50));
//
//        XWPFParagraph paragraph2 = document.createParagraph();
//        paragraph2.setAlignment(ParagraphAlignment.CENTER);
//        XWPFRun run = paragraph2.createRun();
//        run.setText("aaaa");
//        paragraph2.createRun().setText("                          ", 0);
//        XWPFRun run2 = paragraph2.createRun();
//        run2.setText("bbb");

//        run.setVerticalAlignment(VerticalAlign.);

//        paragraph.createRun().setText("-------");
//        paragraphs.get(0).getCTP().newCursor().insertElementWithText("w:p", "ffffff");

//        System.out.println("componentResults.weight".contains(MULTI_FIELD_SEPERATOR));
//        System.out.println(JSON.toJSONString("componentResults.weight".split(MULTI_FIELD_SEPERATOR)));
//        System.out.println(PatternUtils.regex("[com.aaa]", MULTI_FIELD_PLACE_HOLDER, 1));

//        String s = "${projectName}位于${projectAddress}，建于${projectCompleteTime}年，荷载等级为城市${projectDesignLevel}级。桥梁跨径布置为${projectBridgeCross}m，桥梁全长${projectDesignLength}m，全宽${projectTotalWidth}m。桥面横向布置为0.30m(栏杆) +4.20m（人行道）+11.00m(行车道) +4.20m（人行道）+0.30m(栏杆) =20.00m。${projectRemark}。\n";
//        System.out.println(JSON.toJSONString(PatternUtils.regexList(s, PLACE_HOLDER, 0)));
//
//        System.out.println(document.getParagraphArray(0).getRuns().get(0).text());
//        XWPFRun run = document.getParagraphArray(0).getRuns().get(0);
//        run.setText("------", 0);
        FileOutputStream fos = new FileOutputStream("C:\\Users\\10419\\Desktop\\bbb31.docx");
        document.write(fos);
        fos.close();
    }

    private static Map<String, Object> buildData() {
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("projectName", "西门大桥");
        dataMap.put("reportCode", "0000");
        dataMap.put("detectionTime", "2023-10-10");
        dataMap.put("projectAddress", "北京市");
        dataMap.put("projectCompleteTime", "2000-10-10");
        dataMap.put("projectDesignLevel", "A类");
        dataMap.put("projectBridgeCross", "(10+12+15)");
        dataMap.put("projectDesignLength", "10.2");

//        Projects projects = new Projects();
//        projects.setBridgeName("西门大桥");
//        dataMap.put("project", projects);
//
//        ImageData imageData = new ImageData();
//        imageData.setUrl("C:\\Users\\10419\\Desktop\\pic\\bb.png");
//        imageData.setFilename("bb.png");
//        imageData.setExt("png");
//        dataMap.put("facade_image", imageData);
//
//        DetectionPerson d1 = new DetectionPerson(1, "1", "1", "1");
//        DetectionPerson d2 = new DetectionPerson(2, "2", "2", "2");
//        List<Object> ds = Arrays.asList(d1, d2);
//        dataMap.put("detetionPerson", ds);
//
//
//        ComponentResult c1 = new ComponentResult("承重构件", "0.70", "0.85", "84.8", "72.38", false);
//        ComponentResult c2 = new ComponentResult("一般承重构件", "0.18", "	0.00", "100.0", "0.0", false);
//        OneLevelComponentResult o1 = new OneLevelComponentResult("上部结构", "87.0", "0.4", Arrays.asList(c1, c2));
//
//        ComponentResult cc1 = new ComponentResult("翼墙、耳墙", "0.02", "0.02", "100.0", "2.06", false);
//        ComponentResult cc2 = new ComponentResult("锥坡、护坡", "0.01", "0.00", "100.0", "0.0", false);
//        ComponentResult cc3 = new ComponentResult("桥墩", "0.30", "0.31", "61.7", "19.1", false);
//        OneLevelComponentResult o2 = new OneLevelComponentResult("下部结构", "76.3", "0.3", Arrays.asList(cc1, cc2, cc3));

        List<Object> objectList = new ArrayList<>();
//        objectList.add(o1);
//        objectList.add(o2);
        dataMap.put("results", objectList);
        dataMap.put("totalScore", "99.9");
        dataMap.put("totalLevel", "一类");

        return dataMap;
    }
}
